package com.macauscholar.pickup.Test

import com.macauscholar.nfctest.base64.BASE64Decoder
import com.macauscholar.nfctest.base64.BASE64Encoder
import zhiyi.com.teacher_app.RsaKey
import java.io.ByteArrayOutputStream
import java.security.*
import java.security.interfaces.RSAPrivateKey
import java.security.interfaces.RSAPublicKey
import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.X509EncodedKeySpec
import java.util.*
import javax.crypto.Cipher

/**
 *  package : com.macauscholar.pickup.Test
 *  author : zhiyi
 *  date : 22/09/2020 11:51 AM
 *  project : pickup
 *  description :
 */


object TestKey {
    private const val KEY_ALGORITHM = "RSA"
    private const val PUBLIC_KEY = "RSAPublicKey"
    private const val PRIVATE_KEY = "RSAPrivateKey"
    private const val SIGNATURE_ALGORITHM = "MD5withRSA"

    /**
     * RSA最大加密明文大小
     */
    private const val MAX_ENCRYPT_BLOCK = 117

    /**
     * RSA最大解密密文大小
     */
    private const val MAX_DECRYPT_BLOCK = 128

    //获得公钥字符串
    @Throws(Exception::class)
    fun getPublicKeyStr(keyMap: Map<String?, Any?>): String {
        //获得map中的公钥对象 转为key对象
        val key = keyMap[PUBLIC_KEY] as Key?
        //编码返回字符串
        return encryptBASE64(key!!.encoded)
    }

    //获得私钥字符串
    @Throws(Exception::class)
    fun getPrivateKeyStr(keyMap: Map<String?, Any?>): String {
        //获得map中的私钥对象 转为key对象
        val key = keyMap[PRIVATE_KEY] as Key?
        //编码返回字符串
        return encryptBASE64(key!!.encoded)
    }

    //获取公钥
    @Throws(Exception::class)
    fun getPublicKey(key: String?): PublicKey {
        val keyBytes: ByteArray = BASE64Decoder().decodeBuffer(key)
        val keySpec = X509EncodedKeySpec(keyBytes)
        val keyFactory = KeyFactory.getInstance(KEY_ALGORITHM)
        return keyFactory.generatePublic(keySpec)
    }

    //获取私钥
    @Throws(Exception::class)
    fun getPrivateKey(key: String?): PrivateKey {
        val keyBytes: ByteArray = BASE64Decoder().decodeBuffer(key)
        val keySpec = PKCS8EncodedKeySpec(keyBytes)
        val keyFactory = KeyFactory.getInstance(KEY_ALGORITHM)
        return keyFactory.generatePrivate(keySpec)
    }

    //解码返回byte
    @Throws(Exception::class)
    fun decryptBASE64(key: String?): ByteArray {
        return BASE64Decoder().decodeBuffer(key)
    }

    //编码返回字符串
    @Throws(Exception::class)
    fun encryptBASE64(key: ByteArray?): String {
        return BASE64Encoder().encodeBuffer(key)
    }

    //***************************签名和验证*******************************
    @Throws(Exception::class)
    fun sign(data: ByteArray?, privateKeyStr: String?): ByteArray {
        val priK = getPrivateKey(privateKeyStr)
        val sig = Signature.getInstance(SIGNATURE_ALGORITHM)
        sig.initSign(priK)
        sig.update(data)
        return sig.sign()
    }

    @Throws(Exception::class)
    fun verify(data: ByteArray?, sign: ByteArray?, publicKeyStr: String?): Boolean {
        val pubK = getPublicKey(publicKeyStr)
        val sig = Signature.getInstance(SIGNATURE_ALGORITHM)
        sig.initVerify(pubK)
        sig.update(data)
        return sig.verify(sign)
    }

    @Throws(Exception::class)
    fun initKey(): Map<String?, Any?> {
        val keyPairGen = KeyPairGenerator
            .getInstance(KEY_ALGORITHM)
        keyPairGen.initialize(1024)
        val keyPair = keyPairGen.generateKeyPair()
        val publicKey = keyPair.public as RSAPublicKey
        val privateKey = keyPair.private as RSAPrivateKey
        val keyMap: MutableMap<String?, Any?> = HashMap(2)
        keyMap[PUBLIC_KEY] = publicKey
        keyMap[PRIVATE_KEY] = privateKey
        return keyMap
    }

    //************************加密解密**************************
    @Throws(Exception::class)
    fun encrypt(plainText: ByteArray, publicKeyStr: String?): ByteArray {
        val publicKey = getPublicKey(publicKeyStr)
        val cipher = Cipher.getInstance(KEY_ALGORITHM)
        cipher.init(Cipher.ENCRYPT_MODE, publicKey)
        val inputLen = plainText.size
        val out = ByteArrayOutputStream()
        var offSet = 0
        var i = 0
        var cache: ByteArray
        while (inputLen - offSet > 0) {
            cache = if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cipher.doFinal(plainText, offSet, MAX_ENCRYPT_BLOCK)
            } else {
                cipher.doFinal(plainText, offSet, inputLen - offSet)
            }
            out.write(cache, 0, cache.size)
            i++
            offSet = i * MAX_ENCRYPT_BLOCK
        }
        val encryptText = out.toByteArray()
        out.close()
        return encryptText
    }

    @Throws(Exception::class)
    fun decrypt(encryptText: ByteArray, privateKeyStr: String?): ByteArray {
        val privateKey = getPrivateKey(privateKeyStr)
        val cipher = Cipher.getInstance(KEY_ALGORITHM)
        cipher.init(Cipher.DECRYPT_MODE, privateKey)
        val inputLen = encryptText.size
        val out = ByteArrayOutputStream()
        var offSet = 0
        var cache: ByteArray
        var i = 0
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            cache = if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cipher.doFinal(encryptText, offSet, MAX_DECRYPT_BLOCK)
            } else {
                cipher.doFinal(encryptText, offSet, inputLen - offSet)
            }
            out.write(cache, 0, cache.size)
            i++
            offSet = i * MAX_DECRYPT_BLOCK
        }
        val plainText = out.toByteArray()
        out.close()
        return plainText
    }

    @JvmStatic
    fun main(args: Array<String>) {
        val keyMap: Map<String?, Any?>
        val cipherText: ByteArray
        val input = "测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试"
        try {
//            keyMap = initKey()
//            val publicKey = getPublicKeyStr(keyMap)
//            println("公钥------------------")
//            println(publicKey)
//            val privateKey = getPrivateKeyStr(keyMap)
//            println("私钥------------------")
//            println(privateKey)
//            println("测试可行性-------------------")
            println("明文=======$input")
            cipherText = encrypt(input.toByteArray(), RsaKey.publicKey)
            //加密后的东西
            println("密文=======" + String(cipherText))
            //开始解密
            val plainText = decrypt(cipherText, RsaKey.privateKey)
            println("解密后明文===== " + String(plainText))
            println("验证签名-----------")
            val str = "被签名的内容"
            println("\n原文:$str")
            val signature = sign(str.toByteArray(), RsaKey.privateKey)
            val status = verify(str.toByteArray(), signature, RsaKey.publicKey)
            println("验证情况：$status")
        } catch (e : Exception) {
            e.printStackTrace()
        }
    }
}
